#pragma once

#include <iostream>
#include <fstream>
#include <stack>
#include <string>
#include <vector>
#include <map>
#include <list>
#include "HashedString.h"

class XMLElement
{
public:
	typedef std::list<XMLElement*> List_t;
	typedef std::map<const HashedString, const std::string> Map_t;
	// Constructors
	~XMLElement();
	XMLElement(std::string tagName);
	// Setters
	void setTagName(std::string tagName);
	void setText(std::string text);
	void setAttribute(std::string name, std::string value);
	// Getters
	std::string getTagName();
	std::string getText();
	std::string getAttribute(std::string name);
	// Element Tree
	void addChildElement(XMLElement* element);
	List_t& getChildElements();
private:
	std::string m_TagName;
	std::string m_Text;
	Map_t m_Attributes;
	List_t m_ChildElements;
};

class XMLReader
{
public:
	XMLReader(std::ifstream& stream);
	XMLElement* parse();
private: 
	std::vector<int> cdata_start;
	std::vector<int> cdata_end;
	std::ifstream& reader;
	std::stack<XMLElement*> elements;
	XMLElement* currentElement;
private:
	char peek();
	void peek(std::vector<int>& buffer);
	void skipWhitespace();
	void skipProlog();
	void skipPrologs();
	std::string readTag();
	std::string readText();
	bool compareIntArrays(const std::vector<int>& a1, const std::vector<int>& a2);
};